﻿
// comAPP2View.cpp: CcomAPP2View 类的实现
//

#include "pch.h"
#include "framework.h"
// SHARED_HANDLERS 可以在实现预览、缩略图和搜索筛选器句柄的
// ATL 项目中进行定义，并允许与该项目共享文档代码。
#ifndef SHARED_HANDLERS
#include "comAPP2.h"
#endif

#include "comAPP2Doc.h"
#include "comAPP2View.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#include "dataStruction.h"
#include "CDialogPen.h"
#include "CDialogModify.h"
#include "CDialogHelp.h"



// CcomAPP2View

IMPLEMENT_DYNCREATE(CcomAPP2View, CView)

BEGIN_MESSAGE_MAP(CcomAPP2View, CView)
	// 标准打印命令
	ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)
	ON_COMMAND(ID_MENU_F_SELECT, &CcomAPP2View::OnMenuFSelect)
	ON_COMMAND(ID_MENU_F_RECT, &CcomAPP2View::OnMenuFRect)
	ON_COMMAND(ID_MENU_F_LINE, &CcomAPP2View::OnMenuFLine)
	ON_COMMAND(ID_MENU_F_ELLIPSE, &CcomAPP2View::OnMenuFEllipse)
	ON_COMMAND(ID_MENU_F_TEXT, &CcomAPP2View::OnMenuFText)
	ON_UPDATE_COMMAND_UI(ID_MENU_F_ELLIPSE, &CcomAPP2View::OnUpdateMenuFEllipse)
	ON_UPDATE_COMMAND_UI(ID_MENU_F_LINE, &CcomAPP2View::OnUpdateMenuFLine)
	ON_UPDATE_COMMAND_UI(ID_MENU_F_RECT, &CcomAPP2View::OnUpdateMenuFRect)
	ON_UPDATE_COMMAND_UI(ID_MENU_F_SELECT, &CcomAPP2View::OnUpdateMenuFSelect)
	ON_UPDATE_COMMAND_UI(ID_MENU_F_TEXT, &CcomAPP2View::OnUpdateMenuFText)
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_COMMAND(ID_MENU_SET_FILLCOLOR, &CcomAPP2View::OnMenuSetFillcolor)
	ON_COMMAND(ID_MENU_SET_FONT, &CcomAPP2View::OnMenuSetFont)
	ON_COMMAND(ID_MENU_SET_PEN, &CcomAPP2View::OnMenuSetPen)
	ON_WM_RBUTTONDOWN()
	ON_COMMAND(ID_MENU_HELP, &CcomAPP2View::OnMenuHelp)
END_MESSAGE_MAP()

// CcomAPP2View 构造/析构

CcomAPP2View::CcomAPP2View() noexcept
{
	// TODO: 在此处添加构造代码
	currentMode = DRAW_MODE_SELECT;  //默认是选择的模式
	MovingStart = FALSE;
	M_Drawing = FALSE;
}

CcomAPP2View::~CcomAPP2View()
{
}

BOOL CcomAPP2View::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: 在此处通过修改
	//  CREATESTRUCT cs 来修改窗口类或样式

	return CView::PreCreateWindow(cs);
}

// CcomAPP2View 绘图

void CcomAPP2View::OnDraw(CDC* pDC)
{
	CcomAPP2Doc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO: 在此处为本机数据添加绘制代码
    //遍历画出
	for (int u = 0; u < pDoc->FigureBuffer.GetSize(); u++)
		pDoc->FigureBuffer[u]->draw(pDC);
}


// CcomAPP2View 打印

BOOL CcomAPP2View::OnPreparePrinting(CPrintInfo* pInfo)
{
	// 默认准备
	return DoPreparePrinting(pInfo);
}

void CcomAPP2View::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: 添加额外的打印前进行的初始化过程
}

void CcomAPP2View::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: 添加打印后进行的清理过程
}


// CcomAPP2View 诊断

#ifdef _DEBUG
void CcomAPP2View::AssertValid() const
{
	CView::AssertValid();
}

void CcomAPP2View::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CcomAPP2Doc* CcomAPP2View::GetDocument() const // 非调试版本是内联的
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CcomAPP2Doc)));
	return (CcomAPP2Doc*)m_pDocument;
}
#endif //_DEBUG


// CcomAPP2View 消息处理程序


void CcomAPP2View::OnMenuFSelect()
{
	// TODO: 在此添加命令处理程序代码
	currentMode = DRAW_MODE_SELECT;
}


void CcomAPP2View::OnMenuFRect()
{
	// TODO: 在此添加命令处理程序代码
	currentMode = DRAW_MODE_RECT;
}


void CcomAPP2View::OnMenuFLine()
{
	// TODO: 在此添加命令处理程序代码
	currentMode = DRAW_MODE_LINE;
}


void CcomAPP2View::OnMenuFEllipse()
{
	// TODO: 在此添加命令处理程序代码
	currentMode = DRAW_MODE_ELLIPSE;
}


void CcomAPP2View::OnMenuFText()
{
	// TODO: 在此添加命令处理程序代码
	currentMode = DRAW_MODE_TEXT;
}



void CcomAPP2View::OnUpdateMenuFEllipse(CCmdUI* pCmdUI)
{
	// TODO: 在此添加命令更新用户界面处理程序代码
	pCmdUI->SetCheck(currentMode == DRAW_MODE_ELLIPSE);
}


void CcomAPP2View::OnUpdateMenuFLine(CCmdUI* pCmdUI)
{
	// TODO: 在此添加命令更新用户界面处理程序代码
	pCmdUI->SetCheck(currentMode == DRAW_MODE_LINE);
}


void CcomAPP2View::OnUpdateMenuFRect(CCmdUI* pCmdUI)
{
	// TODO: 在此添加命令更新用户界面处理程序代码
	pCmdUI->SetCheck(currentMode == DRAW_MODE_RECT);
}


void CcomAPP2View::OnUpdateMenuFSelect(CCmdUI* pCmdUI)
{
	// TODO: 在此添加命令更新用户界面处理程序代码
	pCmdUI->SetCheck(currentMode == DRAW_MODE_SELECT);
}


void CcomAPP2View::OnUpdateMenuFText(CCmdUI* pCmdUI)
{
	// TODO: 在此添加命令更新用户界面处理程序代码
	pCmdUI->SetCheck(currentMode == DRAW_MODE_TEXT);
}




void CcomAPP2View::OnLButtonDown(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	if (currentMode == DRAW_MODE_LINE
		|| currentMode == DRAW_MODE_RECT
		|| currentMode == DRAW_MODE_ELLIPSE
		|| currentMode == DRAW_MODE_TEXT)
	{
		ptS = point;
		SetCapture();      //不要忘了设置捕捉
		M_Drawing = TRUE;  //进入正在绘制状态
	}
	else if (currentMode == DRAW_MODE_SELECT)
	{
		if (SelectFigureIndex >= 0)
		{
			if (IfPointInFigure(point, GetDocument()->FigureBuffer[SelectFigureIndex]))
			{
				MovingStart = TRUE;
			}
		}
	}




	CView::OnLButtonDown(nFlags, point);
}


void CcomAPP2View::OnLButtonUp(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	if (currentMode == DRAW_MODE_SELECT && MovingStart == FALSE)
	{
		int currentSelect = -1;

		//遍历看是否选中（先遍历在判断，这样在相同的面积上可以选中最后一个）
		for (int i = 0; i < GetDocument()->FigureBuffer.GetSize(); i++)
		{
			if (IfPointInFigure(point, GetDocument()->FigureBuffer[i]))
			{
				currentSelect = i;
			}
		}

		//如果搜索到了(就是说点到了图形)防止重复点击
		if (currentSelect >= 0)
		{
			if (SelectFigureIndex == -1)  //之前没有选中的
			{
				//新建修饰类并初始化
				CSelectDecor* pDecor = new CSelectDecor();
				pDecor->SetDestFigure(GetDocument()->FigureBuffer[currentSelect]);
				//并且使用它内存中替换该类
				GetDocument()->FigureBuffer[currentSelect] = pDecor;
				//记录选中索引
				SelectFigureIndex = currentSelect;
				//刷新界面
				InvalidateRect(NULL);
			}
			else if (SelectFigureIndex >= 0)  //如果之前有选中
			{
			    //恢复以前的
				//新建修饰类并初始化
				CSelectDecor* pDecor = new CSelectDecor();
				//父类指针用子类特有方法，进行强转
				pDecor = dynamic_cast<CSelectDecor*>(GetDocument()->FigureBuffer[SelectFigureIndex]);
				CFigure* OldFigure = pDecor->GetDestFigure();
				//再把原来的内容写回去，替换掉修饰类
				GetDocument()->FigureBuffer[SelectFigureIndex] = OldFigure;

				//选中现在的
				//新建修饰类并初始化
				CSelectDecor* pDecor1 = new CSelectDecor();
				pDecor1->SetDestFigure(GetDocument()->FigureBuffer[currentSelect]);
				//并且使用它内存中替换该类
				GetDocument()->FigureBuffer[currentSelect] = pDecor1;
				//记录选中索引
				SelectFigureIndex = currentSelect;
				//刷新界面
				InvalidateRect(NULL);

			}
			
		}
		else   //如果没有搜索到，就是说点击了空白
		{
			//如果之前有选中，取消选中
			if (SelectFigureIndex >= 0)
			{
				//新建修饰类并初始化
				CSelectDecor* pDecor = new CSelectDecor();
				//父类指针用子类特有方法，进行强转
				pDecor = dynamic_cast<CSelectDecor*>(GetDocument()->FigureBuffer[SelectFigureIndex]);
				CFigure* OldFigure = pDecor->GetDestFigure();
				//再把原来的内容写回去，替换掉修饰类
				GetDocument()->FigureBuffer[SelectFigureIndex] = OldFigure;
				//清除选择索引(选择索引非负就代表选中，为-1代表没选中)
				SelectFigureIndex = -1;
			}
		
			//刷新页面
			InvalidateRect(NULL);
		}


	}
	else  //如果不是图像选择
	{
		CFigure* pNew = NULL;  //父类指针管理子类对象
		if (currentMode == DRAW_MODE_LINE)
		{
			ptE = point;
			pNew = new CMyLine(ptS,ptE);
			
			//释放捕捉
			if (M_Drawing == TRUE)
			{
				ReleaseCapture();
				M_Drawing = FALSE;
			}

			//添加到缓冲区中
			if (pNew)
			{
				if (GetDocument()->AddOneFigureToBuffer(pNew))
				{
					InvalidateRect(NULL);//刷新
				}
			}
		}
		else if (currentMode == DRAW_MODE_RECT)
		{
			ptE = point;
			pNew = new CMyRect(ptS, ptE);

			//释放捕捉
			if (M_Drawing == TRUE)
			{
				ReleaseCapture();
				M_Drawing = FALSE;
			}

			//添加到缓冲区中
			if (pNew)
			{
				if (GetDocument()->AddOneFigureToBuffer(pNew))
				{
					InvalidateRect(NULL);//刷新
				}
			}
		}
		else if (currentMode == DRAW_MODE_ELLIPSE)
		{
			if (M_Drawing == TRUE)
			{
				ptE = point;
				pNew = new CMyElli(ptS, ptE);

				//释放捕捉
				if (M_Drawing == TRUE)
				{
					ReleaseCapture();
					M_Drawing = FALSE;
				}

				//添加到缓冲区中
				if (pNew)
				{
					if (GetDocument()->AddOneFigureToBuffer(pNew))
					{
						InvalidateRect(NULL);//刷新
					}
				}


				M_Drawing = FALSE;
			}
		}
		else if (currentMode == DRAW_MODE_TEXT)
		{
			ptE = point;
			CString tempStr;

			//释放捕捉(如果调用对话框的话一定要，在调用对话框之前放弃捕捉，这个很重要)
			if (M_Drawing == TRUE)
			{
				ReleaseCapture();
				M_Drawing = FALSE;
			}
			//调用对话框获取文本
			CDialogText dialogT;
			if (dialogT.DoModal() == IDOK)
			{
				//利用函数直接读取
				//pNew = new CMyText(ptS,ptE, dialogT.textDirectInput);
			    //使用DDX内存交换的数据
				pNew = new CMyText(ptS, ptE, dialogT.textDDXInput);
			}
            
			if (pNew)
			{
				if (GetDocument()->AddOneFigureToBuffer(pNew))
				{
					InvalidateRect(NULL);//刷新
				}
			}
		}
	}

	//如果图像正在移动
	if (MovingStart == TRUE)
	{
		//强制类型转换
		//父类指针用子类特有方法，进行强转
		CSelectDecor* pDecor = NULL;
		pDecor = dynamic_cast<CSelectDecor*>(GetDocument()->FigureBuffer[SelectFigureIndex]);

		if (pDecor->SelectFigure->Figure == F_LINE)
		{
			CRect tempRect = GetDocument()->FigureBuffer[SelectFigureIndex]->OutRect;
			int tempWidth = tempRect.right - tempRect.left;
			int tempHigh = tempRect.bottom - tempRect.top;
			//重新计算位置
			pDecor->OutRect.left = point.x - tempWidth / 2;
			pDecor->OutRect.top = point.y - tempHigh / 2;
			pDecor->OutRect.right = point.x + tempWidth / 2;
			pDecor->OutRect.bottom = point.y + tempHigh / 2;
			//修改图形位置
			pDecor->SelectFigure->OutRect.left = point.x - tempWidth / 2;
			pDecor->SelectFigure->OutRect.top = point.y - tempHigh / 2;
			pDecor->SelectFigure->OutRect.right = point.x + tempWidth / 2;
			pDecor->SelectFigure->OutRect.bottom = point.y + tempHigh / 2;
			//强转线
			CMyLine* Line = dynamic_cast<CMyLine*>(pDecor->SelectFigure);
			
			//修改线的起末点
			if (Line->ptLS.x <= Line->ptLE.x)
			{
				if (Line->ptLS.y <= Line->ptLE.y)  //左上右下
				{
					Line->ptLS.x = Line->OutRect.left;
			        Line->ptLS.y = Line->OutRect.top;
					Line->ptLE.x = Line->OutRect.right;
					Line->ptLE.y = Line->OutRect.bottom;
				}
				else                                //左下右上    
				{
					Line->ptLS.x = Line->OutRect.left;
					Line->ptLS.y = Line->OutRect.bottom;
					Line->ptLE.x = Line->OutRect.right;
					Line->ptLE.y = Line->OutRect.top;
				}
			}
			else
			{
				if (Line->ptLS.y < Line->ptLE.y)    //右上左下
				{
					Line->ptLS.x = Line->OutRect.right;
					Line->ptLS.y = Line->OutRect.top;
					Line->ptLE.x = Line->OutRect.left;
					Line->ptLE.y = Line->OutRect.bottom;
				}
				else                                //右下左上
				{
					Line->ptLS.x = Line->OutRect.right;
					Line->ptLS.y = Line->OutRect.bottom;
					Line->ptLE.x = Line->OutRect.left;
					Line->ptLE.y = Line->OutRect.top;
				}
			}
			InvalidateRect(NULL); //刷新
		}
		else
		{
			CRect tempRect = GetDocument()->FigureBuffer[SelectFigureIndex]->OutRect;
			int tempWidth = tempRect.right - tempRect.left;
			int tempHigh = tempRect.bottom - tempRect.top;
			//重新计算位置
			pDecor->OutRect.left = point.x - tempWidth / 2;
			pDecor->OutRect.top = point.y - tempHigh / 2;
			pDecor->OutRect.right = point.x + tempWidth / 2;
			pDecor->OutRect.bottom = point.y + tempHigh / 2;
			//修改图形位置
			pDecor->SelectFigure->OutRect.left = point.x - tempWidth / 2;
			pDecor->SelectFigure->OutRect.top = point.y - tempHigh / 2;
			pDecor->SelectFigure->OutRect.right = point.x + tempWidth / 2;
			pDecor->SelectFigure->OutRect.bottom = point.y + tempHigh / 2;

			InvalidateRect(NULL); //刷新
		}

		//结束移动状态
		MovingStart = FALSE;
	}

	CView::OnLButtonUp(nFlags, point);
}

//选择填充颜色
void CcomAPP2View::OnMenuSetFillcolor()
{
	// TODO: 在此添加命令处理程序代码
	CColorDialog dlg;
	if (dlg.DoModal() == IDOK)
	{
		currentBrushColor = dlg.GetColor();
	}
}


void CcomAPP2View::OnMenuSetFont()
{
	// TODO: 在此添加命令处理程序代码
	CFontDialog dialog;
	if (dialog.DoModal() == IDOK)
	{
		dialog.GetCurrentFont(&currentFont);
		currentTextColor = dialog.GetColor();
	}
}


void CcomAPP2View::OnMenuSetPen()
{
	// TODO: 在此添加命令处理程序代码
	CDialogPen dialog;
	if (dialog.DoModal() == IDOK)
	{

	}
}

#define LINE_RANGE 15
BOOL IfPointInFigure(POINT point, CFigure* MFigure)
{
	//线的话，除了判断面积，还要判断距离
	if (MFigure->Figure == F_LINE)
	{
		//利用父类指针，引用子类的特有方法，必须进行强转为子类指针。
		CMyLine* Line = dynamic_cast<CMyLine*>(MFigure);
		if (Line != nullptr)
		{
			if (IfPointBelongToRectArea(point, Line->OutRect))
			{
				if (distanceCalculate(point, Line->ptLS, Line->ptLE) <= LINE_RANGE)
				{
					return TRUE;
				}
			}
		}	
	}
	else //其他情况只判断矩形面积就行
	{
		if (IfPointBelongToRectArea(point, MFigure->OutRect))
		{
			return TRUE;
		}
	}

	return FALSE;
}

/*
 * name：IfPointBelongToRectArea
 * parameter： point（点的位置）、mRect要判断的矩形
 * return：    属于返回True，不属于返回False
 * function： 根据面积法判断点是否属于矩形
 */
BOOL IfPointBelongToRectArea(POINT point, CRect mRect)
{
	//前期已统一，左上右下矩形
	if (point.x >= mRect.left && point.x <= mRect.right && point.y <= mRect.bottom && point.y >= mRect.top)         
	{
		return TRUE;
	}
	return FALSE;
}

/*
 * name：distanceCalculate
 * parameter： point（点的位置）
 *             lineStart、lineEnd 直线上的任意两个点
 * return： 无
 * function： 计算点到直线的距离
 */
DOUBLE distanceCalculate(POINT point, POINT lineStart, POINT lineEnd)
{
	//处理斜率不存在的情况
	if (lineStart.x == lineEnd.x)
	{
		return fabs(point.x - lineStart.x);
	}

	//计算斜截式直线参数y=kx+b
	double k, b;
	k = (lineStart.y - lineEnd.y) * 1.0 / (lineStart.x - lineEnd.x);
	b = lineStart.y - lineStart.x * k;

	//带入公式求距离
	double res = fabs(k * point.x - point.y + b) / sqrt(k * k + 1);

	return res;
}

void CcomAPP2View::OnRButtonDown(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	if (SelectFigureIndex >= 0)
	{
		if (IfPointInFigure(point, GetDocument()->FigureBuffer[SelectFigureIndex]))
		{
			DialogSelectFigureDecor = dynamic_cast<CSelectDecor*>(GetDocument()->FigureBuffer[SelectFigureIndex]);
			CDialogModify dialog;
			int result = dialog.DoModal();
			if (result == ID_DELETE)//删除当前选中
			{
				//删除选择的元素
				GetDocument()->FigureBuffer.RemoveAt(SelectFigureIndex);
				SelectFigureIndex = -1;  //清除选择
				InvalidateRect(NULL); //刷新
			}
			else if (result == ID_MODIFY)  //修改当前选中
			{
				//修改所选择的元素
				GetDocument()->FigureBuffer.SetAt(SelectFigureIndex, DialogSelectFigureDecor->SelectFigure);
				SelectFigureIndex = -1;  //清除选择
				InvalidateRect(NULL);//刷新
			}
		}
	}
	





	CView::OnRButtonDown(nFlags, point);
}

//重写这个方法实现按键响应
BOOL CcomAPP2View::PreTranslateMessage(MSG* pMsg)
{
	// TODO: 在此添加专用代码和/或调用基类
	//按键的处理
	if (pMsg->message == WM_KEYDOWN)
	{
		//delete按键
		if (pMsg->wParam == VK_DELETE)
		{
			if (SelectFigureIndex >= 0)  //如果有选中的话
			{
				//删除选择的元素
				GetDocument()->FigureBuffer.RemoveAt(SelectFigureIndex);
				SelectFigureIndex = -1;  //清除选择
				InvalidateRect(NULL); //刷新
			}
			return TRUE; // 返回TRUE表示已经处理了该消息
		}
		
	}

	return CView::PreTranslateMessage(pMsg);
}


void CcomAPP2View::OnMenuHelp()
{
	// TODO: 在此添加命令处理程序代码
	CDialogHelp dialog;
	dialog.DoModal();
}
